package script;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import main.ConditionException;
import main.ErrorException;
import ui.OutputThread;
import ui.Window;
import xml.XmlDoc;
import code.BaseOut;
import config.ConfigMaker;
import config.ConfigType;
import define.CharSet;
import define.CodeOut;
import define.Common;
import define.ComputeResult;
import define.Config;
import define.ErrorDefine;
import define.FunctionType;
import define.Keyword;
import define.VariableType;
import excelBase.BaseContent;
import excelBase.ExcelData;
import excelBase.ExcelFile;
import excelBase.Sheet;
import file.RichFile;
import font.Atlas;
import font.AtlasVar;
import font.Font;
import font.FontAtlas;
import font.ImageInfo;


public class Function extends VariableContainer implements BaseExpress
{
	private FunctionType m_type;
	private Script m_script;
	private int m_start;
	private int m_end;
	private ArrayList<Express> m_children;
	private ArrayList<BaseExpress> m_parameters;
	private String m_name;
	
	public Function(Script script, int start, int end, VariableContainer father) throws ErrorException
	{
		super(father, script.getGlobalVariables());
		m_script = script;
		m_father = father;
		m_start = start;
		m_end = end;
		m_children = new ArrayList<>();
		m_parameters = new ArrayList<>();
		init();
	}
	
	private void init() throws ErrorException
	{
		int start = findNextNotBlank(m_start + 1, m_end);
		int end = findNextBlank(start + 1, m_end - 1) - 1;
		String name = Common.buildString(m_script.m_scriptCode, start, end);
		m_type = FunctionType.hasFunction(name);
		if(m_type == null)
		{
			throw new ErrorException(ErrorDefine.E_NO_FUNCTION_ERROR, name, m_start);
		}
		makeParam(end + 1);
		makeChildren(end + 1);
		makeType();
	}
	
	public String getName()
	{
		return m_name;
	}
	
	public void addParamter(StringBuffer value, int index)
	{
		if(m_variableList == null)
		{
			return;
		}
		if(index < m_variableList.size())
		{
			m_variableList.get(index).setStringValue(value);
		}
	}
	
	public void addParamter(Variable var, int index)
	{
		if(m_variableList == null)
		{
			return;
		}
		if(index < m_variableList.size())
		{
			m_variableList.get(index).changeToList();
			ArrayList<StringBuffer> list = m_variableList.get(index).getValueList();
			for(StringBuffer sb: var.getValueList())
			{
				list.add(sb);
			}
		}
	}
	
	public void resetFunctionParam()
	{
		if(m_variableList == null)
		{
			return;
		}
		for(Variable var: m_variableList)
		{
			var.setStringValue(new StringBuffer(""));
			var.cancelListMapToVariable();
		}
	}
	
	public StringBuffer getFunctionValue() throws ErrorException
	{
		return m_children.get(0).getValue();
	}
	
	private void makeType() throws ErrorException
	{
		switch(m_type) 
		{
		case E_FOR_FT:
			makeFor();
			break;
		case E_IF_FT:
			makeIf();
			break;
		case E_SWITCH_FT:
			makeSwitch();
			break;
		case E_SET_FT:
			makeSet();
			break;
		case E_ADD_FT:
			makeAdd();
			break;
		case E_DEL_FT:
			makeDel();
			break;
		case E_EXE_FT:
			makeExe();
			break;
		case E_REPLACE_FT:
			makeReplace();
			break;
		case E_SPLIT_FT:
			makeSplit();
			break;
		case E_SUB_FT:
			makeSub();
			break;
		case E_CALL_FT:
			makeCall();
			break;
		case E_RECEIVE_FT:
			makeReceive();
			break;
		case E_PAUSE_FT:
			makePause();
			break;
		case E_BREAK_FT:
			makeBreak();
			break;
		case E_COM_FT:
			makeCom();
			break;
		case E_SAVE_FT:
			makeSave();
			break;
		case E_APPEND_FT:
			makeAppend();
			break;
		case E_XML_FT:
			makeXml();
			break;
		case E_LMX_FT:
			makeLmx();
			break;
		case E_CODE_FT:
			makeCode();
			break;
		case E_COPY_FT:
			makeCopy();
			break;
		case E_FUN_FT:
			makeFunction();
			break;
		case E_FONT_FT:
			makeFont();
			break;
		case E_FONT_OUT_FT:
			makeFontOut();
			break;
		case E_CONFIG_FT:
			makeConfig();
			break;
		case E_ATLAS_FT:
			makeAtlas();
			break;
		case E_ATLAS_OUT_FT:
			makeAtlasOut();
			break;
		default:
			break;
		}
	}
	
	private void makeParam(int start) throws ErrorException
	{
		int end = Common.find(Keyword.E_FUN_CHILD_START_KEY.getCode(), m_script.m_scriptCode, start, m_end);
		if(end == Config.NO_FIND)
		{
			end = m_end;
		}
		--end;
		start = findNextNotBlank(start, end);
		while(start <= end)
		{
			int stop = findNextBlank(start, end) - 1;
			m_parameters.add(getParam(start, stop));
			start = findNextNotBlank(stop + 1, end);
		}
	}
	
	private BaseExpress getParam(int start, int end) throws ErrorException
	{
		if(m_script.m_scriptCode[start] == Keyword.E_CELL_KEY.getCode())
		{
			return new Cell(m_script, start, end, m_father);
		}
		return new Variable(m_script, start, end);
	}
	
	private void makeChildren(int start) throws ErrorException
	{
		start = Common.find(Keyword.E_FUN_CHILD_START_KEY.getCode(), m_script.m_scriptCode, start, m_end);
		while(start != Config.NO_FIND)
		{
			int end = Common.findRelative(start, m_script.m_scriptCode, m_end);
			if(end == Config.NO_FIND)
			{
				throw new ErrorException(ErrorDefine.E_EXP_NOT_MATCH_ERROR, start);
			}
			m_children.add(new Express(m_script, start + 1, end - 1, this));
			start = Common.find(Keyword.E_FUN_CHILD_START_KEY.getCode(), m_script.m_scriptCode, end + 1, m_end);
		}
	}
	
	private int findNextNotBlank(int start, int end) throws ErrorException
	{
		while(start <= end)
		{
			if(Common.isBlank(m_script.m_scriptCode[start]))
			{
				++start;
			}
			else if(m_script.m_scriptCode[start] == Keyword.E_WHOLE_WORD_START.getCode())
			{
				int index = Common.findRelative(start, m_script.m_scriptCode, m_end);
				if(index == Config.NO_FIND || index > end)
				{
					throw new ErrorException(ErrorDefine.E_EXP_NOT_MATCH_ERROR, start);
				}
				else if(index == start + 1)
				{
					start = index + 1;
				}
				else
				{
					break;
				}
			}
			else
			{
				break;
			}
		}
		return start;
	}
	
	private int findNextBlank(int start, int end) throws ErrorException
	{
		while (start <= end) 
		{
			if(Common.isBlank(m_script.m_scriptCode[start]))
			{
				break;
			}
			else if(m_script.m_scriptCode[start] == Keyword.E_WHOLE_WORD_START.getCode())
			{
				int index = Common.findRelative(start, m_script.m_scriptCode, end);
				if(index == Config.NO_FIND)
				{
					throw new ErrorException(ErrorDefine.E_EXP_NOT_MATCH_ERROR, start);
				}
				start = index + 1;
			}
			else
			{
				++start;
			}
		}
		return start;
	}
	
	private void makeFor() throws ErrorException
	{
		if(m_parameters.size() < 2 || m_parameters.size() > 4)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_parameters.get(0).getType() != VariableType.E_VARIABLE_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_parameters.get(0).getStart());
		}
		if(m_parameters.get(1).getType() != VariableType.E_CELL_VT 
				&& m_parameters.get(1).getType() != VariableType.E_VARIABLE_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_parameters.get(1).getStart());
		}
		addVariable((Variable)m_parameters.get(0));
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeIf() throws ErrorException
	{
		if(m_children.size() != 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void addParamterBetweenChildren() throws ErrorException
	{
		int blankIndex = -1;
		for(int i = 0, max = m_children.size() - 1; i < max; ++i)
		{
			int start = m_children.get(i).getEnd() + 2;
			int end = m_children.get(i + 1).getStart() - 2;
			start = findNextNotBlank(start, end);
			if(start > end)
			{
				if(blankIndex < 0)
				{
					blankIndex = i;
				}
				continue;
			}
			else if(blankIndex >= 0)
			{
				throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_children.get(blankIndex).getEnd() + 1);
			}
			end = findNextBlank(start, end);
			m_parameters.add(new Variable(m_script, start, end - 1));
		}
	}
	
	private void makeSwitch() throws ErrorException
	{
		if(m_parameters.size() < 1 || m_parameters.size() > 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_start);
		}
		addParamterBetweenChildren();
		if(m_parameters.size() != m_children.size() && m_parameters.size() != m_children.size() + 1)
		{
			throw new ErrorException(ErrorDefine.E_PARAM_CHILD_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeSet() throws ErrorException
	{
		if(m_parameters.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_parameters.get(0).getType() != VariableType.E_VARIABLE_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_start);
		}
		addParamterBetweenChildren();
		if(m_parameters.size() > 1)
		{
			if(m_parameters.size() - m_children.size() != 1)
			{
				throw new ErrorException(ErrorDefine.E_PARAM_CHILD_NUMBER_ERROR, m_start);
			}
		}
	}
	
	private void makeAtlas() throws ErrorException
	{
		if(m_parameters.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		addParamterBetweenChildren();
		if(m_parameters.size() > 1)
		{
			if(m_parameters.size() - m_children.size() != 1)
			{
				throw new ErrorException(ErrorDefine.E_PARAM_CHILD_NUMBER_ERROR, m_start);
			}
		}
	}
	
	private void makeAtlasOut() throws ErrorException
	{
		if(m_parameters.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeAdd() throws ErrorException
	{
		if(m_parameters.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_parameters.get(0).getType() != VariableType.E_VARIABLE_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_start);
		}
		addParamterBetweenChildren();
		if(m_children.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
		if(m_parameters.size() > 1)
		{
			if(m_parameters.size() - m_children.size() != 1)
			{
				throw new ErrorException(ErrorDefine.E_PARAM_CHILD_NUMBER_ERROR, m_start);
			}
		}
	}
	
	private void makeDel() throws ErrorException
	{
		if(m_parameters.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(((Variable)m_parameters.get(0)).getType() != VariableType.E_VARIABLE_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_start);
		}
		if(m_children.size() == 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeExe() throws ErrorException
	{
		if(m_parameters.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeReplace() throws ErrorException
	{
		if(m_parameters.size() > 2 || m_parameters.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeSplit() throws ErrorException
	{
		if(m_parameters.size() != 2 || m_parameters.get(0).getType() != VariableType.E_VARIABLE_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeSub() throws ErrorException
	{
		if(m_parameters.size() != 1 && m_parameters.size() != 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeCall() throws ErrorException
	{
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeReceive() throws ErrorException
	{
		for(BaseExpress var: m_parameters)
		{
			if(var.getType() != VariableType.E_VARIABLE_VT)
			{
				throw new ErrorException(ErrorDefine.E_PARAMETER_MUST_VARIABLE_ERROR, var.getStart());
			}
		}
		if(m_children.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makePause() throws ErrorException
	{
		if(m_parameters.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeBreak() throws ErrorException
	{
		if(m_parameters.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
		if(!checkIsFor())
		{
			throw new ErrorException(ErrorDefine.E_BREAK_ERROR, m_start);
		}
	}
	
	private void makeCom() throws ErrorException
	{
		if(m_parameters.size() > 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeSave() throws ErrorException
	{
		if(m_parameters.size() > 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeAppend() throws ErrorException
	{
		if(m_parameters.size() > 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeXml() throws ErrorException
	{
		if(m_parameters.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_parameters.get(0).getType() != VariableType.E_CELL_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_parameters.get(0).getStart());
		}
		if(m_children.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeLmx() throws ErrorException
	{
		if(m_parameters.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_parameters.get(0).getType() != VariableType.E_CELL_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_parameters.get(0).getStart());
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeCode() throws ErrorException
	{
		if(m_parameters.size() != 1 && m_parameters.size() != 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeCopy() throws ErrorException
	{
		if(m_parameters.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 2)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeFunction() throws ErrorException
	{
		if(m_father.getFather() != null)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_DEFINE_ERROR, m_start);
		}
		if(m_parameters.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_parameters.get(0).getType() != VariableType.E_STRING_VT)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_NAME_MUST_STRING_ERROR, m_start);
		}
		for(int i = 1, len = m_parameters.size(); i < len; ++i)
		{
			if(m_parameters.get(i).getType() != VariableType.E_VARIABLE_VT)
			{
				throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_ERROR, m_parameters.get(i).getStart());
			}
			addVariable((Variable)m_parameters.get(i));
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
		m_name = m_parameters.get(0).getValue().toString();
		m_script.addFunction(this);
	}
	
	private void makeFont() throws ErrorException
	{
		if(m_parameters.size() < 2 || m_parameters.size() > 3)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeFontOut() throws ErrorException
	{
		if(m_parameters.size() < 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private void makeConfig() throws ErrorException
	{
		if(m_parameters.size() != 0)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_PARAM_NUMBER_ERROR, m_start);
		}
		if(m_children.size() != 1)
		{
			throw new ErrorException(ErrorDefine.E_FUNCTION_CHILDREN_NUMBER_ERROR, m_start);
		}
	}
	
	private boolean checkIsFor()
	{
		VariableContainer father = m_father;
		while(father != null)
		{
			if(father.getFunctionType() == FunctionType.E_FOR_FT)
			{
				return true;
			}
			father = father.getFather();
		}
		return false;
	}
	
	public StringBuffer getValue() throws ErrorException
	{
		switch(m_type) 
		{
		case E_FOR_FT:
			return out_for();			
		case E_IF_FT:
			return out_if();			
		case E_SWITCH_FT:
			return out_switch();			
		case E_SET_FT:
			return out_set();	
		case E_ADD_FT:
			return out_add();
		case E_DEL_FT:
			return out_del();
		case E_EXE_FT:
			return out_exe();			
		case E_REPLACE_FT:
			return out_replace();	
		case E_SPLIT_FT:
			return out_split();
		case E_SUB_FT:
			return out_sub();
		case E_CALL_FT:
			return out_call();			
		case E_RECEIVE_FT:
			return out_receive();			
		case E_PAUSE_FT:
			return out_pause();			
		case E_BREAK_FT:
			return out_break();			
		case E_COM_FT:
			return out_com();			
		case E_SAVE_FT:
			return out_save(false);	
		case E_APPEND_FT:
			return out_save(true);
		case E_XML_FT:
			return out_xml();	
		case E_LMX_FT:
			return out_lmx();
		case E_CODE_FT:
			return out_code();
		case E_COPY_FT:
			return out_copy();
		case E_FUN_FT:
			return out_function();
		case E_FONT_FT:
			return out_font();
		case E_FONT_OUT_FT:
			return out_fontOut();
		case E_CONFIG_FT:
			return out_config();
		case E_ATLAS_FT:
			return out_atlas();
		case E_ATLAS_OUT_FT:
			return out_atlas_out();
		default:
			return new StringBuffer("");
		}
	}

	public VariableType getType()
	{
		return null;
	}

	public int getStart()
	{
		return m_start;
	}
	
	private StringBuffer out_for() throws ErrorException
	{
		VariableType vt = m_parameters.get(1).getType();
		Cell cell = null;
		Variable var = null;
		int end = 0;
		BaseContent base = null;
		if(vt == VariableType.E_CELL_VT)
		{
			cell = (Cell)m_parameters.get(1);
			base = cell.getLastBase();
			end = base.getChildNumber();
		}
		else
		{
			var = (Variable)m_parameters.get(1); 
			var = this.getVariable(var.getName());
			if(var == null || var.getType() != VariableType.E_LIST_VT)
			{
				throw new ErrorException(ErrorDefine.E_FOR_MUST_USE_LIST_ERROR, m_parameters.get(1).getStart());
			}
			end = var.getValueList().size();
		}
		Variable start = (Variable)m_variableList.get(0);
		if(m_parameters.size() >= 3)
		{
			String value = getVariableValue(m_parameters.get(2)).toString();
			Integer temp = Common.isInt(value);
			if(temp == null)
			{
				if(base == null)
				{
					throw new ErrorException(ErrorDefine.E_LIST_ONLY_TAKE_NUMBER_ERROR, m_parameters.get(2).getStart());
				}
				int index = base.hasChild(value);
				if(index == Config.NO_FIND)
				{
					throw new ErrorException(ErrorDefine.E_VARIABLE_MUST_NUMBER_ERROR, m_parameters.get(2).getStart());
				}
				start.setIntValue(index);
			}
			else
			{
				if(temp < 0 || temp >= end)
				{
					throw new ErrorException(ErrorDefine.E_OUT_RANGE_ERROR, m_parameters.get(2).getStart());
				}
				start.setIntValue(temp);
			}
		}
		else
		{
			start.setIntValue(0);
		}
		if(m_parameters.size() >= 4)
		{
			String value = getVariableValue(m_parameters.get(3)).toString();
			Integer temp = Common.isInt(value);
			if(temp == null)
			{
				if(base == null)
				{
					throw new ErrorException(ErrorDefine.E_LIST_ONLY_TAKE_NUMBER_ERROR, m_parameters.get(3).getStart());
				}
				end = base.hasChild(value);
				if(end == Config.NO_FIND)
				{
					throw new ErrorException(ErrorDefine.E_PARAMETER_MUST_VARIABLE_ERROR, m_parameters.get(3).getStart());
				}
			}
			else
			{
				if(temp >= end)
				{
					throw new ErrorException(ErrorDefine.E_OUT_RANGE_ERROR, m_parameters.get(3).getStart());
				}
				else
				{
					end = temp;
				}
			}
			++end;
		}
		StringBuffer out = new StringBuffer("");
		for(int i = start.getIntValue(); i < end; ++i)
		{
			if(vt == VariableType.E_CELL_VT)
			{
				start.setStringValue(new StringBuffer("" + i));
			}
			else
			{
				start.setStringValue(var.getValueList().get(i));
			}
			out.append(m_children.get(0).getValue());
		}
		Common.m_isBreakFor = false;
		return out;
	}
	
	private StringBuffer out_if() throws ErrorException
	{
		String[] temp = new String[m_parameters.size()];
		boolean judge = false;
		for(int i = 0, max = m_parameters.size(); i < max; ++i)
		{
			temp[i] = getVariableValue(m_parameters.get(i)).toString();
		}
		try 
		{
			Condition con = new Condition(temp, 0, temp.length - 1, this);
			judge = con.getValue();
		} 
		catch(ConditionException e) 
		{
			throw new ErrorException(e.getError(), m_parameters.get(e.getPosition()).getStart());
		}
		return m_children.get(judge? 0: 1).getValue();
	}
	
	private StringBuffer out_switch() throws ErrorException
	{
		StringBuffer out = new StringBuffer("");
		String value = getVariableValue(m_parameters.get(0)).toString();
		for(int i = 1, max = m_parameters.size(); i < max; ++i)
		{
			if(value.compareTo(getVariableValue(m_parameters.get(i)).toString()) == 0)
			{
				return m_children.get(i - 1).getValue();
			}
		}
		if(m_parameters.size() == m_children.size() + 1)
		{
			return out;
		}
		return m_children.get(m_children.size() - 1).getValue();
	}
	
	private StringBuffer out_del() throws ErrorException
	{
		Variable var = getVariable(((Variable)m_parameters.get(0)).getName());
		if(var == null)
		{
			throw new ErrorException(ErrorDefine.E_NO_VARIABLE_ERROR, ((Variable)m_parameters.get(0)).getName(), m_parameters.get(0).getStart());
		}
		ArrayList<Integer> indexs = new ArrayList<Integer>();
		ArrayList<StringBuffer> values = new ArrayList<StringBuffer>();
		if(var.getType() == VariableType.E_LIST_VT || var.getType() == VariableType.E_MAP_VT)
		{
			for(int i = 0, size = m_children.size(); i < size; ++i)
			{
				StringBuffer value = m_children.get(i).getValue();
				boolean isIndex = true;
				if(value.charAt(0) == Keyword.E_CELL_STRING_KEY.getChar())
				{
					isIndex = false;
					value.delete(0, 1);
				}
				if(var.getType() == VariableType.E_LIST_VT)
				{
					if(isIndex)
					{
						Integer index = Common.isInt(value.toString());
						if(index == null)
						{
							throw new ErrorException(ErrorDefine.E_LIST_INDEX_MUST_NUMBER_ERROR, value.toString(), m_children.get(i).getStart());
						}
						indexs.add(index);
					}
					else
					{
						values.add(value);
					}
				}
				else
				{
					if(isIndex)
					{
						var.removeByKey(value.toString());
					}
					else
					{
						var.removeByValue(value);
					}
				}
			
			}
			if(indexs.size() > 0)
			{
				var.removeByIndex(indexs, m_start);
			}
			if(values.size() > 0)
			{
				for(StringBuffer v: values)
				{
					var.removeByValue(v);
				}
			}
		}
		else
		{
			throw new ErrorException(ErrorDefine.E_VARIABLE_MUST_LIST_MAP_ERROR, var.getName(), m_parameters.get(0).getStart());
		}
		return new StringBuffer("");
	}
	
	private StringBuffer out_add() throws ErrorException
	{
		Variable var = getVariable(((Variable)m_parameters.get(0)).getName());
		if(var == null)
		{
			throw new ErrorException(ErrorDefine.E_NO_VARIABLE_ERROR, ((Variable)m_parameters.get(0)).getName(), m_parameters.get(0).getStart());
		}
		if(m_parameters.size() == 1)
		{
			if(var.getType() == VariableType.E_VARIABLE_VT)
			{
				var.changeToList();
				for(Express ex: m_children)
				{
					var.getValueList().add(ex.getValue());
				}
			}
			else if(var.getType() == VariableType.E_LIST_VT)
			{
				for(Express ex: m_children)
				{
					var.getValueList().add(ex.getValue());
				}
			}
			else 
			{
				throw new ErrorException(ErrorDefine.E_VARIABLE_NOT_LIST_ERROR, ((Variable)m_parameters.get(0)).getName(), m_parameters.get(0).getStart());
			}
		}
		else
		{
			if(var.getType() == VariableType.E_VARIABLE_VT)
			{
				var.changeToMap();
				for(int i = 1, max = m_parameters.size(); i < max; ++i)
				{
					var.addKeyValue(getVariableValue(m_parameters.get(i)).toString(), m_children.get(i - 1).getValue());
				}
			}
			else if(var.getType() == VariableType.E_MAP_VT)
			{
				for(int i = 1, max = m_parameters.size(); i < max; ++i)
				{
					var.addKeyValue(getVariableValue(m_parameters.get(i)).toString(), m_children.get(i - 1).getValue());
				}
			}
			else 
			{
				throw new ErrorException(ErrorDefine.E_VARIABLE_NOT_MAP_ERROR, ((Variable)m_parameters.get(0)).getName(), m_parameters.get(0).getStart());
			}
		}
		return new StringBuffer("");
	}
	
	private StringBuffer out_set() throws ErrorException
	{
		if(m_children.size() == 0)
		{
			((Variable)m_parameters.get(0)).setStringValue(new StringBuffer(""));
		}
		else if(m_parameters.size() == 1)
		{
			if(m_children.size() == 1)
			{
				((Variable)m_parameters.get(0)).setStringValue(m_children.get(0).getValue());
			}
			else
			{
				Variable var = (Variable)m_parameters.get(0);
				var.changeToList();
				for(Express ex: m_children)
				{
					var.getValueList().add(ex.getValue());
				}
			}
		}
		else
		{
			Variable var = (Variable)m_parameters.get(0);
			var.changeToMap();
			for(int i = 1, max = m_parameters.size(); i < max; ++i)
			{
				var.addKeyValue(getVariableValue(m_parameters.get(i)).toString(), m_children.get(i - 1).getValue());
			}
		}
		m_script.setGlobalVariable((Variable)(m_parameters.get(0)));
		return new StringBuffer("");
	}
	
	private StringBuffer out_exe() throws ErrorException
	{
		Script script = new Script(m_children.get(0).getValue(), m_script.getExcel(), m_script.getGlobalVariables(), this);
		return script.getValue();
	}
	
	private StringBuffer out_replace() throws ErrorException
	{
		StringBuffer old = getVariableValue(m_parameters.get(0));
		StringBuffer newBuffer;
		if(m_parameters.size() > 1)
		{
			newBuffer = getVariableValue(m_parameters.get(1));
		}
		else
		{
			newBuffer = new StringBuffer("");
		}
		StringHander sh = new StringHander(m_children.get(0).getValue());
		return sh.replace(old.toString(), newBuffer.toString());
	}
	
	private StringBuffer out_split() throws ErrorException
	{
		StringBuffer des = getVariableValue(m_parameters.get(1));
		Variable var = (Variable)m_parameters.get(0);
		var.changeToList();
		StringHander sh = new StringHander(m_children.get(0).getValue());
		ArrayList<String> list = sh.split(des.toString());
		for(String temp: list)
		{
			var.getValueList().add(new StringBuffer(temp));
		}
		m_script.setGlobalVariable(var);
		return new StringBuffer("");
	}
	
	private StringBuffer out_sub() throws ErrorException
	{
		StringBuffer start = getVariableValue(m_parameters.get(0));
		StringBuffer end = new StringBuffer("-1");
		if(m_parameters.size() == 2)
		{
			end = getVariableValue(m_parameters.get(1));
		}
		StringHander sh = new StringHander(m_children.get(0).getValue());
		return sh.sub(start.toString(), end.toString());
	}
	
	private StringBuffer out_call() throws ErrorException
	{
		String name = m_children.get(0).getValue().toString();
		Function fun = m_script.getFunction(name);
		if(fun != null)
		{
			fun.resetFunctionParam();
			for(int i = 0, max = m_parameters.size(); i < max; ++i)
			{
				if(m_parameters.get(i).getType() == VariableType.E_VARIABLE_VT)
				{
					Variable var = (Variable)m_parameters.get(i);
					var = this.getVariable(var.getName());
					if(var.getType() == VariableType.E_LIST_VT)
					{
						fun.addParamter(var, i);
					}
					else
					{
						fun.addParamter(var.getValue(), i);
					}
				}
				else
				{
					fun.addParamter(this.getVariableValue(m_parameters.get(i)), i);
				}
			}
			return fun.getFunctionValue();
		}
		Script script = ExcelData.getScript(name);
		if(script == null)
		{
			throw new ErrorException(ErrorDefine.E_CANT_FIND_SCRIPT_ERROR, name, m_parameters.get(0).getStart());
		}
		script.clearReceiveList();
		script.clearGlobalList();
		for(int i = 0, max = m_parameters.size(); i < max; ++i)
		{
			script.addReceiveVariable(getVariableValue(m_parameters.get(i)));
		}
		try 
		{
			return script.getValue();
		}
		catch(ErrorException e) 
		{
			throw new ErrorException(ErrorDefine.E_CALL_SCRIPT_ERROR, name, m_start);
		}
	}
	
	private StringBuffer out_receive() throws ErrorException
	{
		ArrayList<StringBuffer> list = m_script.getReceiveList();
		int len = list.size();
		for(int i = 0, max = m_parameters.size(); i < max; ++i)
		{
			Variable var = (Variable)m_parameters.get(i);
			if(i < len)
			{
				var.setStringValue(list.get(i));
			}
			else
			{
				var.setStringValue(new StringBuffer(""));
			}
			m_script.setGlobalVariable(var);
		}
		return new StringBuffer("");
	}
	
	private StringBuffer out_pause() throws ErrorException
	{
		StringBuffer out = m_children.get(0).getValue();
		if(Common.m_hasUI)
		{
			Window.m_instance.addText("pause: " + out.toString());
			OutputThread.m_instance.hang(m_start);
		}
		else
		{
			System.out.println(out.toString());
		}
		return new StringBuffer("");
	}
	
	private StringBuffer out_break() throws ErrorException
	{
		Common.m_isBreakFor = true;
		return new StringBuffer("");
	}
	
	private StringBuffer out_com() throws ErrorException
	{
		StringBuffer value = m_children.get(0).getValue();
		if(value.indexOf(";") >= 0 || value.indexOf("\n") >= 0 || value.indexOf("\r") >= 0)
		{
			throw new ErrorException(ErrorDefine.E_NO_SEMICOLON_ERROR, m_start);
		}
		ComputeResult cr = ComputeResult.E_DOUBLE_CR;
		if(m_parameters.size() > 0)
		{
			String result = getVariableValue(m_parameters.get(0)).toString();
			cr = ComputeResult.getComputeResult(result);
			if(cr == null)
			{
				throw new ErrorException(ErrorDefine.E_NO_COMPUTE_TYPE_ERROR, result, m_parameters.get(0).getStart());
			}
		}
		ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
		double number = 0;
		try
		{
			number = (double)engine.eval(value.toString());
		} 
		catch(Exception e)
		{
			throw new ErrorException(ErrorDefine.E_COMPUTE_ILLEGAL_ERROR, m_start);
		}
		String out = null;
		if(ComputeResult.isChangeToInt(cr))
		{
			out = String.valueOf(ComputeResult.changeToInt(number, cr));
		}
		else
		{
			out = number + "";
		}
		return new StringBuffer(out);
	}
	
	private StringBuffer out_save(boolean isAppend) throws ErrorException
	{
		String name = m_children.get(0).getValue().toString();
		StringBuffer buf = m_children.get(1).getValue();
		CharSet cs = CharSet.E_ANS_CS;
		if(m_parameters.size() > 0)
		{
			String text = getVariableValue(m_parameters.get(0)).toString();
			cs = CharSet.getCharSet(text);
			if(cs == null)
			{
				throw new ErrorException(ErrorDefine.E_UNKNOWN_CHARSET_ERROR, text, m_start);
			}
		}
		save(name, buf, isAppend, cs);
		return new StringBuffer("");
	}
	
	private StringBuffer out_xml() throws ErrorException
	{
		Sheet sheet = ((Cell)m_parameters.get(0)).getSheet();
		XmlDoc doc = sheet.getXmlDoc(m_start);
		return doc.getValue();
	}
	
	private StringBuffer out_lmx() throws ErrorException
	{
		String path = m_children.get(0).getValue().toString();
		path = m_script.getExcel().getPath() + path;
		XmlDoc doc = new XmlDoc(path, m_start);
		Cell cell = (Cell)m_parameters.get(0);
		ExcelFile excel = cell.getExcel();
		doc.addToExcel(excel, cell.getSheetName(), m_start);
		excel.writeToExecl(m_start);
		return new StringBuffer("");
	}
	
	private StringBuffer out_code() throws ErrorException
	{
		String nameSpace = m_children.get(0).getValue().toString();
		String lang = getVariableValue(m_parameters.get(0)).toString();
		CodeOut co = CodeOut.getCodeOut(lang);
		if(co == null)
		{
			throw new ErrorException(ErrorDefine.E_NO_LANGUAGE_ERROR, m_start);
		}
		boolean isAllowSet = m_parameters.size() > 1;
		BaseOut out = co.getOut(isAllowSet, nameSpace);
		String path = m_script.getOutDir();
		File file = new File(path);
		if(!file.exists())
		{
			if(!file.mkdir())
			{
				throw new ErrorException(ErrorDefine.E_CANT_WRITE_CODE_ERROR, path, m_start);
			}
		}
		out.save(path, m_start);
		return new StringBuffer("");
	}
	
	private StringBuffer out_copy() throws ErrorException
	{
		StringBuffer src = m_children.get(0).getValue();
		StringBuffer des = m_children.get(1).getValue();
		RichFile rf = new RichFile(src.toString(), m_children.get(0).getStart());
		RichFile desRf = new RichFile(des.toString(), m_children.get(1).getStart());
		rf.copy(desRf, true);
		return new StringBuffer("");
	}
	
	private StringBuffer out_function() throws ErrorException
	{
		return new StringBuffer("");
	}
	
	private StringBuffer out_font() throws ErrorException
	{
		String name = getVariableValue(m_parameters.get(0)).toString();
		String fontName = null;
		Integer size = Common.isInt(getVariableValue(m_parameters.get(1)).toString());
		if(size == null)
		{
			throw new ErrorException(ErrorDefine.E_SIZE_NO_INT_ERROR, m_parameters.get(1).getStart());
		}
		if(m_parameters.size() == 3)
		{
			fontName = getVariableValue(m_parameters.get(2)).toString();
		}
		Font f = m_script.addFont(name, fontName, size, m_start);
		StringBuffer str = m_children.get(0).getValue();
		f.addChar(str);
		return new StringBuffer("");
	}
	
	private StringBuffer out_fontOut() throws ErrorException
	{
		FontAtlas fa = new FontAtlas(ConfigType.E_FONT_IMAGE_SIZE_CT.getIntValue());
		String path = m_children.get(0).getValue().toString();
		for(BaseExpress be: m_parameters)
		{
			String name = getVariableValue(be).toString();
			Font f = m_script.getFont(name);
			if(f == null)
			{
				throw new ErrorException(ErrorDefine.E_NO_FONT_ERROR, name, be.getStart());
			}		
			f.addToAtlas(fa);
		}
		fa.output(path, ConfigType.E_FONT_BG_COLOR_CT.createColor(ConfigType.E_FONT_BG_COLOR_CT.getLongValue()),
				m_start);
		return new StringBuffer("");
	}
	
	private StringBuffer out_config() throws ErrorException
	{
		String text = m_children.get(0).getValue().toString();
		String[] strs = text.split(" ");
		new ConfigMaker(strs, 0, strs.length - 1, m_start);
		return new StringBuffer("");
	}
	
	private StringBuffer out_atlas() throws ErrorException
	{
		String name = getVariableValue(m_parameters.get(0)).toString();
		AtlasVar av = m_script.addAtlas(name);
		for(int i = 0, max = m_children.size(); i < max; ++i)
		{
			String key = getVariableValue(m_parameters.get(i + 1)).toString();
			StringBuffer path = m_children.get(i).getValue();
			av.addImageInfo(new ImageInfo(path, key));
		}
		return new StringBuffer("");
	}
	
	private StringBuffer out_atlas_out() throws ErrorException
	{
		String name = getVariableValue(m_parameters.get(0)).toString();
		String path = m_children.get(0).getValue().toString();
		AtlasVar av = m_script.getAtlas(name);
		if(av == null)
		{
			throw new ErrorException(ErrorDefine.E_CANT_FIND_ATLAS_ERROR, name, m_parameters.get(0).getStart());
		}
		Atlas at = new Atlas(ConfigType.E_ATLAS_SIZE_CT.getIntValue());
		av.addToAtlas(at);
		at.output(path, ConfigType.E_ATLAS_BG_COLOR_CT.createColor(ConfigType.E_ATLAS_BG_COLOR_CT.getLongValue()),
				m_start);
		return new StringBuffer("");
	}

	public FunctionType getFunctionType() 
	{
		return m_type;
	}
	
	public boolean compareHas(int position, boolean isWantHas) throws ErrorException
	{
		BaseExpress cell = m_parameters.get(position - 1);
		if(cell.getType() != VariableType.E_CELL_VT)
		{
			throw new ErrorException(ErrorDefine.E_HAS_MUST_FOR_CELL_ERROR, cell.getStart());
		}
		BaseContent base = ((Cell)cell).getLastBase();
		String name = getVariableValue(m_parameters.get(position + 1)).toString();
		boolean isHas = base.hasChild(name) != Config.NO_FIND;
		return isHas == isWantHas;
	}
	
	private void save(String name, StringBuffer buf, boolean isAppend, CharSet cs) throws ErrorException
	{
		String out = Common.m_path + name;
		BufferedWriter writer = null;
		try 
		{
			File file = new File(Common.getPath(out));
			file.mkdirs();
			FileOutputStream fos = new FileOutputStream(out, isAppend);
			writer = new BufferedWriter(new OutputStreamWriter(fos, cs.getCharset()));
			writer.write(buf.toString());
			writer.flush();
			writer.close();
		} 
		catch(Exception e) 
		{
			throw new ErrorException(ErrorDefine.E_CANT_WRITE_SCRIPT_ERROR, name, Config.NO_POSITION);
		}
		finally
		{
			if(writer != null)
			{
				try 
				{
					writer.close();
				}catch(Exception e2) 
				{
				}
			}
		}
	}
}
